package api

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
	"go-malphite/app/common/constant"
	"go-malphite/app/common/dto"
	"go-malphite/app/common/enum"
	"go-malphite/app/common/middleware"
	"go-malphite/app/common/resp"
	"go-malphite/app/model"
	"go-malphite/app/service"
	"go-malphite/app/utils"
	"math/rand"
	"strconv"
)

// CreateUser
// @Summary 用户新增
// @Tags 用户模块
// @Param req body model.UserRegisterParams true "用户注册参数"
// @Success 200 {object} resp.Response{}
// @Router /api/v1/user/register [post]
func CreateUser(c *gin.Context) {
	var params model.UserRegisterParams
	err := c.ShouldBindBodyWith(&params, binding.JSON)
	if err != nil {
		for _, err := range err.(validator.ValidationErrors) {
			if err.Field() == "UserName" {
				if err.Tag() == "required" {
					resp.FailWithMsg(c, "用户名不能为空！")
					return
				}
				if err.Tag() == "min" {
					resp.FailWithMsg(c, fmt.Sprintf("用户名长度不能小于%v", err.Param()))
					return
				}
				if err.Tag() == "max" {
					resp.FailWithMsg(c, fmt.Sprintf("用户名长度不能超过%v", err.Param()))
					return
				}
			}
			if err.Field() == "Password" {
				if err.Tag() == "min" {
					resp.FailWithMsg(c, fmt.Sprintf("密码长度不能小于%v", err.Param()))
					return
				}
				if err.Tag() == "max" {
					resp.FailWithMsg(c, fmt.Sprintf("密码长度不能超过%v", err.Param()))
					return
				}
			}
			if err.Field() == "RePassword" {
				resp.FailWithMsg(c, "两次密码不一致！")
				return
			}
		}

		resp.FailWithMsg(c, "请求参数格式错误！")
		return
	}

	exists := service.IsExistsUserByName(params.UserName)
	if exists {
		resp.FailWithMsg(c, "用户名已注册！")
		return
	}

	role, err := service.FindRoleByType(enum.RoleTypeUser)
	if err != nil {
		resp.FailWithMsg(c, "角色查询失败！")
		return
	}

	user := model.User{}
	user.UserId = dto.GenID()
	user.UserName = params.UserName
	user.Salt = fmt.Sprintf("%06d", rand.Int31())
	user.Password = utils.MakePassword(params.Password, user.Salt)
	user.RoleId = role.RoleId

	success := service.CreateUser(user)
	if success {
		resp.OkWithMsg(c, "用户注册成功！")
		return
	}
	resp.FailWithMsg(c, "用户注册失败！")
}

// LoginUser
// @Summary 用户登录
// @Tags 用户模块
// @Param req body model.UserLoginParams true "用户登录参数"
// @Success 200 {object} resp.Response{data=model.UserLoginRes}
// @Router /api/v1/user/login [post]
func LoginUser(c *gin.Context) {
	var params model.UserLoginParams
	err := c.ShouldBindBodyWith(&params, binding.JSON)
	if err != nil {
		resp.FailWithMsg(c, "请求参数格式错误！")
		return
	}
	if params.CaptchaKey == "" || params.CaptchaCode == "" {
		resp.FailWithMsg(c, "验证码不能为空！")
		return
	}
	flag := service.VerifyCaptcha(params.CaptchaKey, params.CaptchaCode)
	if !flag {
		resp.FailWithMsg(c, "验证码错误！")
		return
	}
	if params.UserName == "" {
		resp.FailWithMsg(c, "用户名不能为空！")
		return
	}
	user, err := service.FindUserByName(params.UserName)
	if err != nil {
		resp.FailWithMsg(c, "该用户不存在！")
		return
	}
	ok := utils.ValidPassword(params.Password, user.Salt, user.Password)
	if !ok {
		resp.FailWithMsg(c, "密码不正确！")
		return
	}
	token, _ := middleware.GenerateToken(strconv.Itoa(int(user.UserId)))
	data := model.UserLoginRes{
		UserId:    user.UserId,
		UserName:  user.UserName,
		CreatedAt: user.CreatedAt.Format(constant.DateTimeFormat),
		UpdatedAt: user.UpdatedAt.Format(constant.DateTimeFormat),
		Token:     "Bearer " + token,
	}
	// 增加redis控制jwt主动注销功能
	err = utils.Redis.Set(token, user.UserId, 0).Err()
	if err != nil {
		resp.FailWithMsg(c, "登录失败！")
		return
	}
	resp.OkWithData(c, data, "登录成功！")
}

// GetDetailUser
// @Summary 用户详情
// @Tags 用户模块
// @Param Authorization header string true "JWT"
// @Success 200 {object} resp.Response{}
// @Router /api/v1/user/detail [get]
func GetDetailUser(c *gin.Context) {
	user := model.User{
		UserId: c.GetInt64(constant.CurrentUserId),
	}
	data, err := service.GetDetailUser(user)
	if err != nil {
		resp.FailWithMsg(c, err.Error())
		return
	}
	resp.OkWithData(c, data, "请求成功")
}

// UpdateUser
// @Summary 修改用户
// @Tags 用户模块
// @Param Authorization header string true "JWT"
// @param req formData model.UserEditParams false "修改用户参数"
// @Success 200 {object} resp.Response{}
// @Router /api/v1/user/update [post]
func UpdateUser(c *gin.Context) {
	user, err := service.FindUserById(c.GetInt64(constant.CurrentUserId))
	if err != nil {
		resp.FailWithMsg(c, "用户不存在！")
		return
	}

	var params model.UserEditParams
	err = c.ShouldBind(&params)
	if err != nil {
		resp.FailWithMsg(c, "请求参数格式错误！")
		return
	}
	if params.UserName == "" {
		resp.FailWithMsg(c, "用户名不能为空！")
		return
	}
	if len([]rune(params.UserName)) < 3 {
		resp.FailWithMsg(c, fmt.Sprintf("用户名长度不能小于%v", 3))
		return
	}
	if len([]rune(params.UserName)) > 30 {
		resp.FailWithMsg(c, fmt.Sprintf("用户名长度不能超过%v", 30))
		return
	}
	if params.OldPassword == "" {
		resp.FailWithMsg(c, "旧密码不能为空！")
		return
	}
	if !utils.ValidPassword(params.OldPassword, user.Salt, user.Password) {
		resp.FailWithMsg(c, "旧密码不正确！")
		return
	}
	if params.NewPassword == "" {
		resp.FailWithMsg(c, "新密码不能为空！")
		return
	}
	if len([]rune(params.NewPassword)) < 6 {
		resp.FailWithMsg(c, fmt.Sprintf("用户名长度不能小于%v", 6))
		return
	}
	if len([]rune(params.NewPassword)) > 100 {
		resp.FailWithMsg(c, fmt.Sprintf("用户名长度不能超过%v", 100))
		return
	}
	if params.NewPassword != params.RePassword {
		resp.FailWithMsg(c, "新密码与确认密码不一致！")
		return
	}

	user.UserName = params.UserName
	user.Salt = fmt.Sprintf("%06d", rand.Int31())
	user.Password = utils.MakePassword(params.NewPassword, user.Salt)

	flag := service.UpdateUser(user)
	if flag {
		resp.OkWithMsg(c, "更新成功！")
		return
	}
	resp.FailWithMsg(c, "更新失败！")
}

// UpdateUserByName
// @Summary 修改用户
// @Tags 用户模块
// @Param Authorization header string true "JWT"
// @param name formData string false "用户名称"
// @Success 200 {object} resp.Response{}
// @Router /api/v1/user/updateByName [post]
func UpdateUserByName(c *gin.Context) {
	user, err := service.FindUserById(c.GetInt64(constant.CurrentUserId))
	if err != nil {
		resp.FailWithMsg(c, "用户不存在！")
		return
	}

	var params model.UserEditParams
	err = c.ShouldBind(&params)
	if err != nil {
		resp.FailWithMsg(c, "请求参数格式错误！")
		return
	}
	if params.UserName == "" {
		resp.FailWithMsg(c, "用户名不能为空！")
		return
	}
	if len([]rune(params.UserName)) < 3 {
		resp.FailWithMsg(c, fmt.Sprintf("用户名长度不能小于%v", 3))
		return
	}
	if len([]rune(params.UserName)) > 30 {
		resp.FailWithMsg(c, fmt.Sprintf("用户名长度不能超过%v", 30))
		return
	}

	user.UserName = params.UserName

	flag := service.UpdateUserForName(user)
	if flag {
		resp.OkWithMsg(c, "更新成功！")
		return
	}
	resp.FailWithMsg(c, "更新失败！")
}

// LogoutUser
// @Summary 用户退出
// @Tags 用户模块
// @Param Authorization header string true "JWT"
// @Success 200 {object} resp.Response{}
// @Router /api/v1/user/logout [post]
func LogoutUser(c *gin.Context) {
	token := c.GetString("token")
	err := utils.Redis.Exists(token).Err()
	if err != nil {
		resp.FailWithMsg(c, "用户未登录！")
		return
	}
	err = utils.Redis.Del(token).Err()
	if err != nil {
		resp.FailWithMsg(c, "用户退出失败！")
		return
	}
	resp.OkWithMsg(c, "用户退出成功！")
}

// GetListUser
// @Summary 用户列表
// @Tags 用户模块
// @Param Authorization header string true "JWT"
// @Success 200 {object} resp.Response{}
// @Router /api/v1/user/list [get]
func GetListUser(c *gin.Context) {
	userList, err := service.GetListUser()
	if err != nil {
		resp.FailWithMsg(c, "查询失败！")
		return
	}
	resp.OkWithData(c, userList, "查询成功！")
}

// GetPageUser
// @Summary 用户列表-分页
// @Tags 用户模块
// @Param Authorization header string true "JWT"
// @param page formData dto.PageReq false "分页"
// @Success 200 {object} resp.Response{}
// @Router /api/v1/user/page [get]
func GetPageUser(c *gin.Context) {
	userList, err := service.GetPageUser(dto.GetPageReq(c))
	if err != nil {
		resp.FailWithMsg(c, "查询失败！")
		return
	}
	resp.OkWithData(c, userList, "查询成功！")
}

// RemoveUser
// @Summary 删除用户
// @Tags 用户模块
// @Param Authorization header string true "JWT"
// @Success 200 {object} resp.Response{}
// @Router /api/v1/user/remove/:userId [post]
func RemoveUser(c *gin.Context) {
	if c.Param("userId") == "" {
		resp.FailWithMsg(c, "用户id不能为空！")
		return
	}

	userId, err := strconv.ParseInt(c.Param("userId"), 10, 64)
	if err != nil {
		resp.FailWithMsg(c, "用户id格式错误！")
		return
	}

	currentUserId, err := strconv.ParseInt(c.GetString(constant.CurrentUserId), 10, 64)
	if err != nil {
		resp.FailWithMsg(c, "当前用户id格式错误")
		return
	}

	if userId == currentUserId {
		resp.FailWithMsg(c, "请使用其它管理员账号进行该操作！")
		return
	}

	user, err := service.FindUserById(userId)
	if err != nil {
		resp.FailWithMsg(c, "用户不存在！")
		return
	}

	flag := service.RemoveUser(user)
	if flag {
		resp.OkWithMsg(c, "删除成功！")
		return
	}
	resp.FailWithMsg(c, "删除失败！")
}
